/*
 * Synchronization primitives
 * Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
 * $Revision: 1.13 $
 * 
 * This is free software.  You are permitted to use,
 * redistribute, and modify it as specified in the file "COPYING".
 */

#include <geekos/kthread.h>
#include <geekos/int.h>
#include <geekos/kassert.h>
#include <geekos/screen.h>
#include <geekos/synch.h>
#include <libc/string.h>
#include <geekos/errno.h>
#include <geekos/bitset.h>
#include <geekos/string.h>
#include <geekos/malloc.h>
/*
 * NOTES:
 * - The GeekOS mutex and condition variable APIs are based on those
 *   in pthreads.
 * - Unlike disabling interrupts, mutexes offer NO protection against
 *   concurrent execution of interrupt handlers.  Mutexes and
 *   condition variables should only be used from kernel threads,
 *   with interrupts enabled.
 */


/* Estructura de un semaforo */
struct Semaphore {
    char name[MAX_LENGTH];    
    int value;
    int refCount;
    struct Mutex mutex;
    struct Condition condition;
};



struct Semaphore semaphores[MAX_SEMAPHORES_COUNT];
extern tlocal_key_t keySem;
static struct Mutex mutex_global = MUTEX_INITIALIZER;


/* ----------------------------------------------------------------------
 * Private functions
 * ---------------------------------------------------------------------- */

/*
 * The mutex is currently locked.
 * Atomically reenable preemption and wait in the
 * mutex's wait queue.
 */
static void Mutex_Wait(struct Mutex *mutex)
{
    KASSERT(mutex->state == MUTEX_LOCKED);
    KASSERT(g_preemptionDisabled);

    Disable_Interrupts();
    g_preemptionDisabled = false;
    Wait(&mutex->waitQueue);
    g_preemptionDisabled = true;
    Enable_Interrupts();
}

/*
 * Lock given mutex.
 * Preemption must be disabled.
 */
static __inline__ void Mutex_Lock_Imp(struct Mutex* mutex)
{
    KASSERT(g_preemptionDisabled);

    /* Make sure we're not already holding the mutex */
    KASSERT(!IS_HELD(mutex));

    /* Wait until the mutex is in an unlocked state */
    while (mutex->state == MUTEX_LOCKED) {
	Mutex_Wait(mutex);
    }

    /* Now it's ours! */
    mutex->state = MUTEX_LOCKED;
    mutex->owner = g_currentThread;
}

/*
 * Unlock given mutex.
 * Preemption must be disabled.
 */
static __inline__ void Mutex_Unlock_Imp(struct Mutex* mutex)
{
    KASSERT(g_preemptionDisabled);

    /* Make sure mutex was actually acquired by this thread. */
    KASSERT(IS_HELD(mutex));

    /* Unlock the mutex. */
    mutex->state = MUTEX_UNLOCKED;
    mutex->owner = 0;

    /*
     * If there are threads waiting to acquire the mutex,
     * wake one of them up.  Note that it is legal to inspect
     * the queue with interrupts enabled because preemption
     * is disabled, and therefore we know that no thread can
     * concurrently add itself to the queue.
     */
    if (!Is_Thread_Queue_Empty(&mutex->waitQueue)) {
	Disable_Interrupts();
	Wake_Up_One(&mutex->waitQueue);
	Enable_Interrupts();
    }
}

/* ----------------------------------------------------------------------
 * Public functions
 * ---------------------------------------------------------------------- */

/*
 * Initialize given mutex.
 */
void Mutex_Init(struct Mutex* mutex)
{
    mutex->state = MUTEX_UNLOCKED;
    mutex->owner = 0;
    Clear_Thread_Queue(&mutex->waitQueue);
}

/*
 * Lock given mutex.
 */
void Mutex_Lock(struct Mutex* mutex)
{
    KASSERT(Interrupts_Enabled());

    g_preemptionDisabled = true;
    Mutex_Lock_Imp(mutex);
    g_preemptionDisabled = false;
}

/*
 * Unlock given mutex.
 */
void Mutex_Unlock(struct Mutex* mutex)
{
    KASSERT(Interrupts_Enabled());

    g_preemptionDisabled = true;
    Mutex_Unlock_Imp(mutex);
    g_preemptionDisabled = false;
}

/*
 * Initialize given condition.
 */
void Cond_Init(struct Condition* cond)
{
    Clear_Thread_Queue(&cond->waitQueue);
}

/*
 * Wait on given condition (protected by given mutex).
 */
void Cond_Wait(struct Condition* cond, struct Mutex* mutex)
{
    KASSERT(Interrupts_Enabled());

    /* Ensure mutex is held. */
    KASSERT(IS_HELD(mutex));

    /* Turn off scheduling. */
    g_preemptionDisabled = true;

    /*
     * Release the mutex, but leave preemption disabled.
     * No other threads will be able to run before this thread
     * is able to wait.  Therefore, this thread will not
     * miss the eventual notification on the condition.
     */
    Mutex_Unlock_Imp(mutex);

    /*
     * Atomically reenable preemption and wait in the condition wait queue.
     * Other threads can run while this thread is waiting,
     * and eventually one of them will call Cond_Signal() or Cond_Broadcast()
     * to wake up this thread.
     * On wakeup, disable preemption again.
     */
    Disable_Interrupts();
    g_preemptionDisabled = false;
    Wait(&cond->waitQueue);
    g_preemptionDisabled = true;
    Enable_Interrupts();

    /* Reacquire the mutex. */
    Mutex_Lock_Imp(mutex);

    /* Turn scheduling back on. */
    g_preemptionDisabled = false;
}

/*
 * Wake up one thread waiting on the given condition.
 * The mutex guarding the condition should be held!
 */
void Cond_Signal(struct Condition* cond)
{
    KASSERT(Interrupts_Enabled());
    Disable_Interrupts();  /* prevent scheduling */
    Wake_Up_One(&cond->waitQueue);
    Enable_Interrupts();  /* resume scheduling */
}

/*
 * Wake up all threads waiting on the given condition.
 * The mutex guarding the condition should be held!
 */
void Cond_Broadcast(struct Condition* cond)
{
    KASSERT(Interrupts_Enabled());
    Disable_Interrupts();  /* prevent scheduling */
    Wake_Up(&cond->waitQueue);
    Enable_Interrupts();  /* resume scheduling */
}


/*Semaphores*/


void Init_Key(){
   
    if(Tlocal_Create(&keySem, (void*)Destructor_All_Semaphores)){
     
    }
}



int Buscar_Sem_Vacio_O_Existente(const char* name, int init_value){

	int i;
	int sem_empty = -1;

	
	/* busca si esta creado el semaforo o guarda en la variable 
	 * sem_emty la pocicion del priemr lugar vacio del arreglo 
	 * de semaforos
	 */
	
	
		/*comienza el tratamiento para la creacion del semaforo*/
		i = 0; 
		for (i = 0; i < MAX_SEMAPHORES_COUNT; i += 1)
        {
			if (semaphores[i].refCount==0)
		   	{
				sem_empty = i;   		
		   	}
			else
			{
				if (strcmp(name,(semaphores[i]).name)==0){					
					(semaphores[i]).refCount++;
                    break;
				}
			}
		}

		/* si estaba creada */
		if (i == MAX_SEMAPHORES_COUNT)
		{
			if (sem_empty == -1){				
				i = ERROR_QUEUE_SEMAPHORE_FULL;
				/*No se puede crear mas semaforos ya que solo se permiten 20*/
			}
			else
			{
        		/* crea el semaforo */
		        i = sem_empty;
			    strcpy(semaphores[i].name,name);
			    semaphores[i].value = init_value;
			    semaphores[i].refCount = 1;
                
                /*Mutex*/
                Mutex_Init(&(semaphores[i].mutex));
		
              	Cond_Init(&(semaphores[i].condition));
            }
        }				
        return i;
}



int Create_Semaphore(const char* name, int init_value){
	int id_sem = -1;
    void *bitset = 0;
    
    KASSERT(Interrupts_Enabled());
	Mutex_Lock(&mutex_global);
   
    id_sem = Buscar_Sem_Vacio_O_Existente(name, init_value);
    
    /* tLocalData */    
    if( id_sem >= 0 ){
        if( Tlocal_Get(keySem) == 0){
            bitset = Create_Bit_Set(MAX_SEMAPHORES_COUNT);
            if(bitset != 0){
                Tlocal_Put(keySem, bitset);
            }
            else{
                goto error;
            }
        }
        Set_Bit(Tlocal_Get(keySem), id_sem);
    }     
    else{
        goto error;
    }
	Mutex_Unlock(&mutex_global);
    return id_sem;

error:
    return -1;
    /*Hacer label*/

}




int p(int i){
	int ret = 0;
	if(!Sem_Held(i)){
            return -1;
    }
	
	Mutex_Lock(&(semaphores[i].mutex));
		if (semaphores[i].value==0){
			Cond_Wait ((&(semaphores[i].condition)), (&(semaphores[i].mutex)));
		}
	semaphores[i].value--;
	Mutex_Unlock(&(semaphores[i].mutex));

	return ret;
}


int v (int i){
	int ret = 0;
	/*
	 * si el semaforo no es un recurso del proceso retorna -1 
	 */
	if(!Sem_Held(i)){
            return -1;
    }
    

	Mutex_Lock(&(semaphores[i].mutex));
	/* Incrementa los recursos disponibles del semaforo y 
	 * manda la señal de activacion para el resto de los procesos 
	 * que requieren dicho recurso y se encuentran en la cola 
	 * de espera.
	 */
			semaphores[i].value++;
			if (semaphores[i].value > 0){
				Cond_Signal(&(semaphores[i].condition));
			}
	Mutex_Unlock(&(semaphores[i].mutex));

	return ret;
}



/*
 * Controla que el proceso corriente contenga el bitSet, ademas de chequear que el 
 * semaforo 'sem_id' este creado para el mismo. Controla tambien que dicho semaforo
 * se encuentre creado en el sistema. 
 *
 */

int Sem_Held(int sem_id){
    void* bitset = Tlocal_Get(keySem);
   
    return (bitset != 0) && (Is_Bit_Set(bitset, sem_id)) && (semaphores[sem_id].refCount > 0);
  
}



int Destroy_Semaphore(int idSem){

    KASSERT(Interrupts_Enabled());
    if (!Sem_Held(idSem)){
        return EINVALID;
    }
	Mutex_Lock(&(semaphores[idSem].mutex));

	if (--semaphores[idSem].refCount == 0){
		semaphores[idSem].name[0] = '\0' ;
	}
	
	/* limpia el bitset */
	Clear_Bit(Tlocal_Get(keySem), idSem);
	
	Mutex_Unlock(&(semaphores[idSem].mutex));
	return 0;		
}


/* destruye todos los semaforos*/
void Destructor_All_Semaphores(void* bitset){
     
    KASSERT(Interrupts_Enabled());   
    int i;
    for(i = 0; i < MAX_SEMAPHORES_COUNT; i++){
        if(Sem_Held(i)){
            Destroy_Semaphore(i);
        }
    }
    Destroy_Bit_Set(bitset);

}
